var CyueEditor = (function () {
  // Android APP
  let jsBridgeLoaded = false;
  if (/(Android)/i.test(navigator.userAgent)) {
    window.onJsBridgeReady = function () {
      jsBridgeLoaded = true;
    };
  }

  /**
   * 将光标移动到最后
   * @param { HTMLElement } element
   */
  function cursorToEnd(element = undefined) {
    if (element) element.focus();
    const selection = window.getSelection();
    const focusNode = selection.focusNode;
    const range = document.createRange();
    range.selectNodeContents(focusNode);
    range.collapse(false);
    selection.removeAllRanges();
    selection.addRange(range);
  }

  /**
   * 将光标移到指定 offset
   * @param { Node } element
   * @param { number } offset
   */
  function cursorToOffset(node, offset) {
    const selection = window.getSelection();
    const range = document.createRange();
    range.collapse();
    range.setStart(node, offset);
    selection.removeAllRanges();
    selection.addRange(range);
  }

  async function openFiles(options = undefined) {
    if (!window.showOpenFilePicker) {
      const input = document.createElement("input");
      input.type = "file";
      if (options) {
        if (options.multiple) input.multiple = "true";

        if (options.accept) {
          if (options.accept instanceof Array)
            input.accept = options.accept.toString();
          else if (options.accept instanceof Object)
            input.accept = Object.keys(options.accept).toString();
        }
      }
      input.style.display = "none";

      return await new Promise((resolve) => {
        input.addEventListener("change", (e) => {
          const files = e.target.files;
          if (!files) resolve([]);
          resolve(files);
          input.remove();
        });
        input.click();
      });
    }

    try {
      const fileHandles = await window.showOpenFilePicker(options);
      const files = new Array(fileHandles.length);
      for (let index = 0; index < fileHandles.length; index++) {
        const handle = fileHandles[index];
        files[index] = await handle.getFile();
      }
      return files;
    } catch (e) {
      console.error(e);
      return [];
    }
  }

  const cyueEditor = {
    contentFocus(e) {
      const element = e.target;
      if (element.id !== "cyue-editor-content") return;
      if (
        !element.innerHTML ||
        element.innerHTML === "<br>" ||
        !element.innerHTML.includes("</p>")
      ) {
        element.addParagraph();
      }
    },

    /**
     * @param {KeyboardEvent} e
     */
    paragraphKeyUp(e) {
      // console.log(e);
      /** @type { HTMLElement } */
      // const editor = e.target.parentElement;
      /** @type { HTMLElement } */
      // const element = e.target;
      // element.setAttribute("contenteditable", "plaintext-only");

      if (e.key === "Backspace") {
        // 移除字体格式
        document.execCommand("removeFormat");
      }
    },

    /**
     * @param {KeyboardEvent} e
     */
    paragraphKeyDown(e) {
      /** @type { HTMLElement } */
      const editor = e.target.parentElement;
      /** @type { HTMLElement } */
      const element = e.target;

      // 回车
      if (e.key === "Enter") {
        e.preventDefault();

        // 光标在开头 或 开始与结尾不重合
        const selection = window.getSelection();
        // console.log(selection);
        if (selection.focusOffset === 0) return;
        if (!selection.collapse) {
          const range = selection.getRangeAt(0);
          cursorToOffset(range.startContainer, range.startOffset);
          return;
        }

        // 删除长按导致的很多 div
        // element.innerHTML = element.innerHTML.replaceAll(/(<\/?(div)?(br)?>)*/g, "");
        // if (!element.innerHTML || element.innerHTML === "<br>")
        // return;

        const range = selection.getRangeAt(0);
        const textNodes = element.childNodes;
        let found = false;
        let tempContent = "";
        for (let index = 0; index < textNodes.length; index++) {
          const node = textNodes[index];
          if (node.isSameNode(range.startContainer)) {
            found = true;
            const cloneNode = node.cloneNode(true);

            // 获取 光标后面的文本
            tempContent = cloneNode.textContent.substring(range.endOffset);
            for (let j = index + 1; j < textNodes.length; j++) {
              const n = textNodes[j];
              tempContent += n.textContent;
            }

            // 获取 光标前面的文本 并 保留
            // 当前 node 部分文本
            const currentTextPart = document.createTextNode(
              cloneNode.textContent.substring(0, range.startOffset),
            );
            for (let j = textNodes.length - 1; j >= index; j--) {
              // 从后往前删掉 node，因为是引用，从前往后会出问题
              const n = textNodes[j];
              element.removeChild(n);
            }
            // 添加部分文本 node
            element.appendChild(currentTextPart);
            break;
          }
        }

        // 没有找到 光标 对应 节点，不添加下一段
        if (!found) return;

        const nextElement = element.nextElementSibling;
        if (nextElement) {
          if (!nextElement.innerHTML) {
            nextElement.innerHTML = tempContent;
            nextElement.focus();
          } else {
            editor.addParagraphAfter(element, tempContent);
          }
        } else {
          editor.addParagraphAfter(element, tempContent);
        }
        return;
      }

      // 在开头退格
      if (e.key === "Backspace") {
        // 移除字体格式
        document.execCommand("removeFormat");

        const selection = window.getSelection();
        // 在开头
        if (selection.focusOffset === 0) {
          const previousElement = element.previousElementSibling;
          if (!element.innerHTML) {
            element.remove();
            cursorToEnd(previousElement);
          }

          // 没有上一个元素
          if (!previousElement) return;

          // 阻止删除原先上一段的最后一个字
          e.preventDefault();
          // 将转义字符变回原来模样
          const tempContent = element.innerHTML
            .replaceAll("&lt;", "<")
            .replaceAll("&gt;", ">")
            .replaceAll("&amp;", "&");
          const tempContentTextNode = document.createTextNode(tempContent);
          previousElement.appendChild(tempContentTextNode);
          previousElement.focus();
          cursorToOffset(tempContentTextNode, 0);

          // 删除 element
          if (element) element.remove();
        }
      }
    },

    /**
     *
     * @param { InputEvent } e
     * @returns
     */
    paragraphOnInput(e) {
      if (!e.data) return;
    },
  };

  /**
   * @type { HTMLElement }
   */
  const cyueEditorContentBase = {
    init() {
      this.id = "cyue-editor-content";
      this.addEventListener("click", cyueEditor.contentFocus);
      this.addEventListener("touchend", cyueEditor.contentFocus);

      // 测试 range
      // this.addEventListener("mouseup", () => {
      //     console.log("Range:", window.getSelection().getRangeAt(0));
      // });

      this.addEventListener("keydown", (e) => {
        // const element = e.target;
        const turnDict = {
          "&": "&",
          "<": "<",
          ">": ">",
        };
        if (e.key === "&" || e.key === "<" || e.key === ">") {
          e.preventDefault();
          const range = window.getSelection().getRangeAt(0);
          const node = document.createTextNode(turnDict[e.key]);
          const offset = node.textContent.length;
          range.insertNode(node);
          range.setStart(node, offset);
        }

        if (e.key === "Shift") {
          document.execCommand("increaseFontSize");
        }
      });
    },

    createParagraph(content = "") {
      const p = document.createElement("p");
      const textNode = document.createTextNode(content);
      p.setAttribute("contenteditable", "true");
      p.addEventListener("keyup", cyueEditor.paragraphKeyUp);
      p.addEventListener("keydown", cyueEditor.paragraphKeyDown);
      p.addEventListener("input", cyueEditor.paragraphOnInput);
      p.appendChild(textNode);
      return p;
    },

    /**
     *
     * @param { string } content
     */
    addParagraph(content = "") {
      // console.log(this)
      const p = this.createParagraph(content);
      this.appendChild(p);
      p.focus();
    },

    /**
     * @param { HTMLElement } node
     * @param { string } content
     */
    addParagraphAfter(node, content = "") {
      const p = this.createParagraph(content);
      node.after(p);
      p.focus();
    },

    /**
     *
     * @returns { string }
     */
    getHTML() {
      // 查最低一级的 element 的 textContent
      // /** @type { (element:HTMLElement) => string } */
      // const getTextContent = (element) => {
      //     if (element.children.length === 0)
      //         return [element.textContent];
      //     const count = element.children.length;
      //     const arr = Array(count);
      //     for (let index = 0; index < count; index++) {
      //         const child = element.children[index];
      //         arr[index] = getTextContent(child);
      //         console.log(arr[index]);
      //     }
      //     return arr;
      // };
      // console.log(getTextContent(this));

      // let content = this.innerHTML.replaceAll(' contenteditable="true"', "").replaceAll(' contenteditable="plaintext-only"', "");
      // content = content.replaceAll("<br>", "");
      // content = content.replaceAll(/(<p?(div)?>(<br>)?(<div>)?(<br>)?(<\/div>)?<\/p?(div)?>)*/g, "");
      // content = content.replaceAll("div", "p");

      // const container = document.createElement("div");
      // /** @type { HTMLCollectionOf<HTMLParagraphElement> } */
      // const paragraphs = this.getElementsByTagName("p");
      // for (let index = 0; index < paragraphs.length; index++) {
      //     const element = paragraphs[index];
      //     const p = document.createElement("p");
      //     p.innerHTML = element.textContent.trim();       // 去除两端空白符
      //     container.appendChild(p);
      // }
      // console.log(container.innerHTML);
      // return container.innerHTML;

      for (let index = 0; index < this.children.length; index++) {
        const element = this.children[index];
        element.innerHTML = element.innerHTML.replaceAll(
          /(<\/?(div)?(br)?>)*/g,
          "",
        );
      }

      return this.innerHTML
        .replaceAll(' contenteditable="true"', "")
        .replaceAll(' contenteditable="plaintext-only"', "")
        .replaceAll("\n", "")
        .replaceAll("&nbsp;", "&amp;nbsp;")
        .replace(/<p>(<br>)?<\/p>/gi, "")
        .replace(/<div[^>]*>([^<]*)<\/div>/gi, "$1") // 去掉 div 标签
        .replace(/<font[^>]*><span[^>]*>([^<]*)<\/span><\/font>/gi, "$1") // 去掉 font 标签
        .replace(/<span[^>]*>([^<]*)<\/span>/gi, "$1") // 去掉 span 标签
        .replace(/<strike>([^<]*)<\/strike>/gi, "<s>$1</s>"); // strike 过时了
    },

    /**
     *
     * @returns { string }
     */
    getArticleContentXML() {
      const parser = new DOMParser();
      const htmlString = this.getHTML();
      const htmlDom = parser.parseFromString(htmlString, "text/html").body;
      for (let index = 0; index < htmlDom.children.length; index++) {
        const element = htmlDom.children[index];
        if (element.tagName === "P") {
          continue;
        } else if (element.tagName === "FIGURE") {
          const figcaption = element.lastElementChild;
          if (figcaption) {
            figcaption.removeAttribute("placeholder");
            if (!figcaption.innerHTML || figcaption.innerHTML === "<br>")
              figcaption.remove();
          }
        }
      }

      const contentDom = document.createElement("content");
      contentDom.setAttribute("xmlns", "http://cyue.net");
      // contentDom.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
      // contentDom.setAttribute("xsi:schemaLocation", "http://cyue.net http://cyue.net/schema/article-content.xsd");
      contentDom.innerHTML = htmlDom.innerHTML;

      const div = document.createElement("div");
      div.appendChild(contentDom);

      // 给所有 img 加个闭口，把 <b> 变 <strong>，把 <i> 变 <em>
      const xmlStr = div.innerHTML
        .replace(/(<img[^>]*>)/g, "$1</img>")
        .replace(/<b>([^<]*)<\/b>/gi, "<strong>$1</strong>")
        .replace(/<i>([^<]*)<\/i>/gi, "<em>$1</em>");
      return xmlStr;
    },
  };

  /**
   * @type { HTMLElement }
   */
  const cyueEditorToolbarBase = {
    init() {
      this.id = "cyue-editor-toolbar";

      const removeTextFormatID = "cyue-editor-toolbar-remove-text-format";
      const toBoldID = "cyue-editor-toolbar-to-bold";
      const toItalicID = "cyue-editor-toolbar-to-italic";
      const underlineID = "cyue-editor-toolbar-underline";
      const strikeThroughID = "cyue-editor-toolbar-strike-through";
      const superscriptID = "cyue-editor-toolbar-superscript";
      const subscriptID = "cyue-editor-toolbar-subscript";

      const insertSubtitleID = "cyue-editor-toolbar-insert-subtitle";
      const insertImageID = "cyue-editor-toolbar-insert-image";
      const clearSpaceID = "cyue-editor-toolbar-clear-space";
      // const insertListOrderedID = "cyue-editor-toolbar-insert-list-ordered"
      // const insertListUnorderedID = "cyue-editor-toolbar-insert-list-unordered";
      this.innerHTML = `
                <div id="${removeTextFormatID}" class="container-icon">
                <svg class="icon" t="1708419610934" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="11946" width="200" height="200"><path d="M512 954.88c-243.712 0-442.88-199.168-442.88-442.88s199.168-442.88 442.88-442.88 442.88 199.168 442.88 442.88-199.168 442.88-442.88 442.88z m0-63.488c208.896 0 379.392-170.496 379.392-379.392s-170.496-379.392-379.392-379.392-379.392 170.496-379.392 379.392 170.496 379.392 379.392 379.392z m221.184-379.392c0 18.944-12.8 31.744-31.744 31.744h-379.392c-18.944 0-31.744-12.8-31.744-31.744s12.8-31.744 31.744-31.744h379.392c19.456 0 31.744 12.8 31.744 31.744z" p-id="11947"></path></svg>
                </div>
                <div id="${toBoldID}" class="container-icon">
                <svg class="icon" t="1708310751008" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5036" width="200" height="200"><path d="M233.078 933.236l0-793.073 281.659 0c86.333 0 152.917 16.369 199.696 49.167s70.196 78.177 70.196 136.198c0 42.992-14.563 80.74-43.574 113.13s-65.536 54.759-109.575 67.051l0 2.038c55.283 6.815 99.964 27.322 133.926 61.458 34.02 34.137 50.973 76.954 50.973 128.509 0 72.002-25.573 129.325-76.78 171.734-51.205 42.526-121.227 63.789-209.949 63.789l-296.572 0zM402.075 266.109l0 196.083 80.39 0c38.623 0 68.973-9.204 91.168-27.67s33.263-44.215 33.263-77.302c0-60.759-44.389-91.109-133.169-91.109l-71.652 0zM402.075 589.711l0 217.58 100.372 0c42.642 0 76.021-9.903 100.14-29.71 24-19.807 36.06-47.302 36.06-82.43 0-33.438-11.942-59.42-35.826-77.827s-57.846-27.67-101.887-27.67l-98.857 0z" fill="#272636" p-id="5037"></path></svg>
                </div>
                <div id="${toItalicID}" class="container-icon">
                <svg class="icon" t="1708405801933" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4200" width="200" height="200"><path d="M768 85.792h-288a32 32 0 0 0 0 64h96.32l-230.336 704H256a32 32 0 0 0 0 64h288a32 32 0 0 0 0-64h-93.728l230.528-704H768a32 32 0 0 0 0-64z" p-id="4201"></path></svg>
                </div>
                <div id="${underlineID}" class="container-icon">
                <svg class="icon" t="1708417673861" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4201" width="200" height="200"><path d="M512 811.296a312 312 0 0 0 312-312V89.6h-112v409.696a200 200 0 1 1-400 0V89.6h-112v409.696a312 312 0 0 0 312 312zM864 885.792H160a32 32 0 0 0 0 64h704a32 32 0 0 0 0-64z" p-id="4202"></path></svg>
                </div>
                <div id="${strikeThroughID}" class="container-icon">
                <svg class="icon" t="1708418349455" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5748" width="200" height="200"><path d="M893.088 501.792H125.344a32 32 0 0 0 0 64h767.744a32 32 0 0 0 0-64zM448 448h112V208h288V96H160v112h288zM448 640h112v288H448z" p-id="5749"></path></svg>
                </div>
                <div id="${superscriptID}" class="container-icon">
                <svg class="icon" t="1708419051588" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6998" width="200" height="200"><path d="M217.856 218a16 16 0 0 1 12.608 6.15L402.06 443.78 573.655 224.15A16 16 0 0 1 586.263 218h82.39a8 8 0 0 1 6.305 12.925L455.358 512 676.52 795.075A8 8 0 0 1 670.217 808h-82.391a16 16 0 0 1-12.608-6.15L402.06 580.219 228.9 801.851A16 16 0 0 1 216.293 808h-82.39a8 8 0 0 1-6.305-12.925l221.163-283.076-219.6-281.074A8 8 0 0 1 135.465 218h82.391zM809.5 104c56.61 0 102.5 45.89 102.5 102.5 0 26.976-10.697 49.264-30.232 67.89l-0.807 0.766c-12.522 11.778-25.321 20.055-50.158 33.802l-11.76 6.469c-23.251 12.853-34.51 20.212-43.935 29.451-3.45 3.383-6.323 6.802-8.64 10.356l-0.237 0.366 137.791 0.378a8 8 0 0 1 7.978 8v36a8 8 0 0 1-8 8h-0.023l-189-0.535a8 8 0 0 1-7.977-8V381.5c0-29.405 11.17-53.621 31.704-73.753l0.86-0.838c13.776-13.316 28.004-22.493 55.676-37.74l8.57-4.706c22.672-12.5 33.27-19.313 42.074-27.706C855.644 227.45 860 218.375 860 206.5c0-27.89-22.61-50.5-50.5-50.5-27.611 0-50.047 22.16-50.493 49.665l-0.007 0.835v3.5a8 8 0 0 1-8 8h-36a8 8 0 0 1-8-8v-3.5c0-56.61 45.89-102.5 102.5-102.5z" p-id="6999"></path></svg>
                </div>
                <div id="${subscriptID}" class="container-icon">
                <svg class="icon" t="1708419330598" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8243" width="200" height="200"><path d="M238.762667 170.666667L448 423.594667 657.237333 170.666667H768l-264.618667 319.872L768 810.410667V810.666667h-110.506667l-209.493333-253.184L238.506667 810.666667H128v-0.256l264.618667-319.872L128 170.666667h110.762667zM919.466667 707.413333a34.133333 34.133333 0 1 0-56.32-15.36l-49.28 14.08a85.333333 85.333333 0 1 1 140.714666 38.570667L885.077333 810.666667H981.333333v42.666666h-170.666666v-42.666666l108.8-103.253334z" p-id="8244"></path></svg>
                </div>

                <div id="${insertSubtitleID}" class="container-icon">
                <svg class="icon" t="1708273198034" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5676" width="200" height="200"><path d="M940.272941 162.032941a286.117647 286.117647 0 0 1 52.404706 180.705883 365.025882 365.025882 0 0 1-55.416471 194.56 851.727059 851.727059 0 0 1-120.470588 132.517647 373.458824 373.458824 0 0 0-105.411764 145.167058h278.889411v120.470589H598.136471a413.214118 413.214118 0 0 1 56.621176-218.654118A894.494118 894.494118 0 0 1 783.058824 561.392941a583.68 583.68 0 0 0 77.703529-92.16 245.157647 245.157647 0 0 0 37.345882-130.108235A168.658824 168.658824 0 0 0 875.218824 240.941176a86.738824 86.738824 0 0 0-74.089412-32.527058 84.329412 84.329412 0 0 0-78.305883 51.802353 331.896471 331.896471 0 0 0-28.310588 146.371764H602.352941A409.6 409.6 0 0 1 657.167059 180.705882a169.261176 169.261176 0 0 1 147.57647-89.750588 163.84 163.84 0 0 1 135.529412 71.077647zM30.72 92.762353h103.604706v838.475294H30.72z" p-id="5677"></path><path d="M452.969412 445.741176v103.604706H44.574118V445.741176z" p-id="5678"></path><path d="M390.324706 92.762353H493.929412v838.475294H390.324706z" p-id="5679"></path></svg>
                </div>
                <div id="${insertImageID}" class="container-icon">
                <svg class="icon" type="file" t="1707115580732" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4223" width="200" height="200"><path d="M896 626.592a16 16 0 0 0-7.68-13.664L715.872 507.84a16 16 0 0 0-20.704 3.52l-76 92.608-1.024 1.152a16 16 0 0 1-22.624 0.032L342.688 353.088a16.032 16.032 0 0 0-22.08-0.512l-187.36 170.656a15.936 15.936 0 0 0-5.248 11.84V800h768V626.592zM736 320a64 64 0 1 0 128 0 64 64 0 1 0-128 0z" p-id="4224"></path><path d="M32 128v768h960V128H32z m896 704H96V192h832v640z" p-id="4225"></path></svg>
                </div>
                <div id="${clearSpaceID}" class="container-icon">
                <svg class="icon" t="1708315001428" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4858" width="200" height="200"><path d="M890.8 133.7v757.1h-757V133.7h757m68.8-68.9H64.9v894.7h894.7V64.8z" p-id="4859"></path><path d="M684.5 615.4v68.8H340.2v-68.8h-68.8v137.7H753.3V615.4zM634 352.2l-48.7-48.7-73 73-73-73-48.7 48.7 73 73-73 73 48.7 48.6 73-73 73 73 48.7-48.6-73-73z" p-id="4860"></path></svg>
                </div>
            `;
      // this.innerHTML = `
      //     <div id="${insertImageID}" class="container-icon">
      //     <svg class="icon" type="file" t="1707115580732" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4223" width="200" height="200"><path d="M896 626.592a16 16 0 0 0-7.68-13.664L715.872 507.84a16 16 0 0 0-20.704 3.52l-76 92.608-1.024 1.152a16 16 0 0 1-22.624 0.032L342.688 353.088a16.032 16.032 0 0 0-22.08-0.512l-187.36 170.656a15.936 15.936 0 0 0-5.248 11.84V800h768V626.592zM736 320a64 64 0 1 0 128 0 64 64 0 1 0-128 0z" p-id="4224"></path><path d="M32 128v768h960V128H32z m896 704H96V192h832v640z" p-id="4225"></path></svg>
      //     </div>
      //     <div id="${insertListOrderedID}" class="container-icon">
      //     <svg class="icon" t="1707217404178" viewBox="0 0 1097 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6049" width="200" height="200"><path d="M330.313143 225.499429v-109.714286h728.356571v109.714286H330.313143z m1.974857 369.005714v-109.714286h728.722286v109.714286H332.288z m-0.438857 365.129143v-109.714286h727.259428v109.714286H331.849143zM179.126857 49.298286v212.992h-58.88V122.733714c-9.508571 7.241143-18.724571 13.092571-27.648 17.554286s-20.041143 8.777143-33.499428 12.873143V105.325714c19.748571-6.363429 35.181714-14.043429 46.08-22.966857 10.971429-8.996571 19.602286-20.041143 25.746285-33.133714h48.201143z m38.4 578.706285H42.934857c2.048-17.261714 8.045714-33.499429 18.285714-48.64 10.093714-15.213714 29.110857-33.133714 57.051429-53.833142 17.042286-12.653714 27.940571-22.235429 32.694857-28.818286a32.329143 32.329143 0 0 0 7.094857-18.724572 21.869714 21.869714 0 0 0-7.021714-16.384 24.649143 24.649143 0 0 0-17.773714-6.729142 24.795429 24.795429 0 0 0-18.285715 6.948571c-4.681143 4.681143-7.826286 12.946286-9.508571 24.722286l-58.221714-4.681143c2.267429-16.384 6.436571-29.184 12.580571-38.4a58.368 58.368 0 0 1 25.746286-21.138286c11.117714-4.900571 26.477714-7.314286 46.08-7.314286 20.48 0 36.425143 2.340571 47.762286 6.948572a58.148571 58.148571 0 0 1 26.916571 21.504c6.509714 9.654857 9.728 20.48 9.728 32.548571a66.56 66.56 0 0 1-11.190857 36.571429c-7.460571 11.629714-21.065143 24.356571-40.740572 38.253714-11.702857 8.045714-19.602286 13.750857-23.552 17.042286a215.259429 215.259429 0 0 0-13.897142 12.653714h90.843428v47.469714zM103.643429 844.8l-55.003429-9.874286a69.046857 69.046857 0 0 1 26.331429-40.228571c13.019429-9.435429 31.451429-14.043429 55.296-14.043429 27.282286 0 47.030857 5.12 59.245714 15.286857 12.214857 10.166857 18.285714 22.966857 18.285714 38.4a42.934857 42.934857 0 0 1-7.387428 24.576 63.122286 63.122286 0 0 1-22.454858 19.309715c8.045714 1.974857 14.262857 4.315429 18.578286 6.948571a45.348571 45.348571 0 0 1 16.237714 16.969143 51.2 51.2 0 0 1 5.778286 25.088 69.851429 69.851429 0 0 1-9.581714 35.108571 64.146286 64.146286 0 0 1-27.574857 25.819429c-11.995429 5.997714-27.794286 9.069714-47.323429 9.069714-19.017143 0-34.011429-2.267429-45.056-6.729143a67.291429 67.291429 0 0 1-27.136-19.675428 90.258286 90.258286 0 0 1-16.384-32.475429l58.148572-7.753143c2.340571 11.702857 5.851429 19.894857 10.678857 24.356572 4.827429 4.534857 10.971429 6.802286 18.285714 6.802286 7.899429 0 14.336-2.852571 19.529143-8.557715a32.694857 32.694857 0 0 0 7.826286-22.820571 31.744 31.744 0 0 0-7.533715-22.601143 26.550857 26.550857 0 0 0-20.333714-8.045714c-4.534857 0-10.825143 1.170286-18.870857 3.437714l2.998857-41.545143a55.588571 55.588571 0 0 0 7.606857 0.731429 26.550857 26.550857 0 0 0 19.017143-7.314286 23.113143 23.113143 0 0 0 7.68-17.261714 20.626286 20.626286 0 0 0-5.705143-15.36 21.211429 21.211429 0 0 0-15.725714-5.632 23.04 23.04 0 0 0-16.749714 6.217143c-4.242286 4.096-7.168 11.410286-8.704 21.796571z" fill="#333333" p-id="6050"></path></svg>
      //     </div>
      //     <div id="${insertListUnorderedID}" class="container-icon">
      //     <svg class="icon" style="transform: translateY(3%);" t="1707218895345" viewBox="0 0 1102 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="16315" width="200" height="200"><path d="M93.105231 187.943385a78.769231 78.769231 0 1 1 0-157.538462 78.769231 78.769231 0 0 1 0 157.538462z m0 393.846153a78.769231 78.769231 0 1 1 0-157.538461 78.769231 78.769231 0 0 1 0 157.538461z m0 393.846154a78.769231 78.769231 0 1 1 0-157.538461 78.769231 78.769231 0 0 1 0 157.538461zM276.243692 161.792v-118.153846h787.692308v118.153846h-787.692308z m0.472616 397.233231v-118.153846h788.007384v118.153846H276.716308z m-3.308308 397.154461v-118.153846h789.267692v118.153846H273.329231z" fill="#333333" p-id="16316"></path></svg>
      //     </div>
      // `;

      // 叫元素渲染出来先
      setTimeout(() => {
        const removeTextFormatICON =
          document.getElementById(removeTextFormatID);
        const toBoldICON = document.getElementById(toBoldID);
        const toItalicICON = document.getElementById(toItalicID);
        const underlineICON = document.getElementById(underlineID);
        const strikeThroughICON = document.getElementById(strikeThroughID);
        const superscriptICON = document.getElementById(superscriptID);
        const subscriptICON = document.getElementById(subscriptID);

        const insertSubtitleICON = document.getElementById(insertSubtitleID);
        const insertImageICON = document.getElementById(insertImageID);
        const clearSpaceICON = document.getElementById(clearSpaceID);
        // const insertListOrderedICON = document.getElementById(insertListOrderedID);
        // const insertListUnorderedICON = document.getElementById(insertListUnorderedID);
        removeTextFormatICON.title = "移除文本效果";
        toBoldICON.title = "加粗";
        toItalicICON.title = "斜体";
        underlineICON.title = "下划线";
        strikeThroughICON.title = "删除线";
        superscriptICON.title = "上标";
        subscriptICON.title = "下标";

        insertSubtitleICON.title = "插入副标题";
        insertImageICON.title = "插入图片";
        // insertListOrderedICON.title = "插入有序列表";
        // insertListUnorderedICON.title = "插入无序列表";
        clearSpaceICON.title = "去除空格（清除段落中的空格）";

        // 文本样式
        removeTextFormatICON.addEventListener("mousedown", () =>
          this.removeTextFormat(),
        );
        removeTextFormatICON.addEventListener("touchstart", () =>
          this.removeTextFormat(),
        );
        toBoldICON.addEventListener("mousedown", () => this.toBold());
        toBoldICON.addEventListener("touchstart", () => this.toBold());
        toItalicICON.addEventListener("mousedown", () => this.toItalic());
        toItalicICON.addEventListener("touchstart", () => this.toItalic());
        underlineICON.addEventListener("mousedown", () => this.underline());
        underlineICON.addEventListener("touchstart", () => this.underline());
        strikeThroughICON.addEventListener("mousedown", () =>
          this.strikeThrough(),
        );
        strikeThroughICON.addEventListener("touchstart", () =>
          this.strikeThrough(),
        );
        superscriptICON.addEventListener("mousedown", () => this.superscript());
        superscriptICON.addEventListener("touchstart", () =>
          this.superscript(),
        );
        subscriptICON.addEventListener("mousedown", () => this.subscript());
        subscriptICON.addEventListener("touchstart", () => this.subscript());

        // 元素
        insertSubtitleICON.addEventListener("click", () =>
          this.insertSubtitle(),
        );
        insertImageICON.addEventListener("click", () => this.insertImage());
        // insertListOrderedICON.addEventListener("click", () => this.insertListOrdered());
        // insertListUnorderedICON.addEventListener("click", () => this.insertListUnordered());
        clearSpaceICON.addEventListener("click", () => this.clearSpace());
      }, 0);
    },

    /**
     * 移除文本效果
     */
    removeTextFormat() {
      document.execCommand("removeFormat");
    },

    /**
     * 加粗
     */
    toBold() {
      document.execCommand("removeFormat");
      document.execCommand("bold");
    },

    /**
     * 倾斜
     */
    toItalic() {
      document.execCommand("removeFormat");
      document.execCommand("italic");
    },

    /**
     * 添加下划线
     */
    underline() {
      document.execCommand("removeFormat");
      document.execCommand("underline");
    },

    /**
     * 添加删除线
     */
    strikeThrough() {
      document.execCommand("removeFormat");
      document.execCommand("strikeThrough");
    },

    /**
     * 上标
     */
    superscript() {
      document.execCommand("removeFormat");
      document.execCommand("superscript");
    },

    /**
     * 下标
     */
    subscript() {
      document.execCommand("removeFormat");
      document.execCommand("subscript");
    },

    /**
     * 插入 副标题
     */
    insertSubtitle() {
      const h2 = document.createElement("h2");
      h2.contentEditable = "plaintext-only";
      h2.addEventListener("keydown", (e) => {
        if (e.key === "Enter") {
          e.preventDefault();
          this.nextElementSibling.addParagraph();
        } else if (e.key === "Backspace") {
          /** @type { HTMLElement } */
          const element = e.target;
          const previousElement = element.previousElementSibling;
          if (!element.innerHTML) {
            element.remove();
            if (previousElement) {
              e.preventDefault();
              cursorToEnd(previousElement);
            }
          }
        }
      });
      this.nextElementSibling.appendChild(h2);
      h2.focus();
    },

    /**
     * 插入图片
     */
    async insertImage() {
      const insert = (imgSrc) => {
        const img = document.createElement("img");
        img.src = imgSrc;

        const figure = document.createElement("figure");
        figure.addEventListener("click", (e) => {
          // 点击 before remove
          const mouseX = e.offsetX;
          const mouseY = e.offsetY;

          const figureStyle = window.getComputedStyle(figure);
          const figurePaddingSize = parseFloat(figureStyle.padding);

          const beforeStyle = window.getComputedStyle(figure, "::before");
          const beforeBorderWidth = parseFloat(beforeStyle.borderWidth);
          const beforeWidth = parseFloat(beforeStyle.width) + beforeBorderWidth;
          const beforeHeight =
            parseFloat(beforeStyle.height) + beforeBorderWidth;
          const beforeX = figure.clientWidth - figurePaddingSize - beforeWidth;

          if (mouseX >= beforeX && mouseY <= beforeHeight) {
            // 后面有 空 paragraph
            if (
              figure.nextElementSibling &&
              (!figure.nextElementSibling.innerHTML ||
                figure.nextElementSibling.innerHTML === "<br>")
            ) {
              figure.nextElementSibling.remove();
            }
            figure.remove();
            return;
          }

          // 点到 figcaption 不处理
          /** @type { HTMLImageElement } */
          const imgElement = figure.firstChild;
          const imgBottom = imgElement.getBoundingClientRect().bottom;
          if (e.pageY >= imgBottom) return;

          // 点击 figure 添加 paragraph
          if (!figure.nextElementSibling) {
            const contentElement = this.nextElementSibling;
            contentElement.addParagraph();
          }
        });

        const figcaption = document.createElement("figcaption");
        const figcaptionPlaceholder = "在此处键入提示词";
        figcaption.setAttribute("placeholder", figcaptionPlaceholder);
        figcaption.addEventListener("focusout", (_e) => {
          if (!figcaption.innerHTML || figcaption.innerHTML === "<br>")
            figcaption.setAttribute("placeholder", figcaptionPlaceholder);
        });
        figcaption.addEventListener("click", (_e) => {
          figcaption.removeAttribute("placeholder");
          figcaption.contentEditable = "plaintext-only";
          figcaption.focus();
        });
        figcaption.addEventListener("keydown", (e) => {
          if (e.key === "Enter") {
            e.preventDefault();
          }
        });
        figcaption.addEventListener("input", (_e) => {});

        figure.appendChild(img);
        figure.appendChild(figcaption);

        this.nextElementSibling.appendChild(figure);
      };

      // Android
      if (jsBridgeLoaded) {
        JsBridge.Util.openAlbum(function (uriString) {
          const imgData = JsBridge.Util.readFileByUriToBase64(uriString);
          if (imgData) insert("data:image/png;base64," + imgData);
        });
        return;
      }

      // 微信
      if (typeof wx !== "undefined" && wx.isReady) {
        const checkWXJsApi = (jsApiList) => {
          return new Promise((resolve) => {
            wx.checkJsApi({
              jsApiList: jsApiList, // 需要检测的JS接口列表，所有JS接口列表见附录2,
              success: function (res) {
                // 以键值对的形式返回，可用的api值true，不可用为false
                // 如：{"checkResult":{"chooseImage":true},"errMsg":"checkJsApi:ok"}
                resolve(res);
              },
            });
          });
        };
        const response = await checkWXJsApi(["chooseImage", "getLocalImgData"]);
        if (
          response.checkResult["chooseImage"] &&
          response.checkResult["getLocalImgData"]
        ) {
          wx.chooseImage({
            count: 1,
            sizeType: ["original", "compressed"], // 可以指定是原图还是压缩图，默认二者都有
            sourceType: ["album", "camera"], // 可以指定来源是相册还是相机，默认二者都有
            success: function (res) {
              var localIds = res.localIds; // 返回选定照片的本地ID列表，localId可以作为img标签的src属性显示图片
              wx.getLocalImgData({
                localId: localIds[0], // 图片的localID
                success: function (res) {
                  var localData = ""; // localData是图片的base64数据，可以用img标签显示
                  if (/Android/i.test(navigator.userAgent))
                    localData = "data:image/png;base64," + res.localData;
                  else localData = res.localData;
                  insert(localData);
                },
              });
            },
          });
          return;
        }
      }

      // common
      const [file] = await openFiles({
        types: [
          {
            description: "图片",
            accept: {
              "image/bmp": [".bmp", ".BMP"],
              "image/jpeg": [".jpg", ".jpeg", ".JPG", ".JPEG"],
              "image/png": [".png", ".PNG"],
              "image/webp": [".webp", ".WEBP"],
              "image/gif": [".gif", ".GIF"],
            },
          },
        ],
        excludeAcceptAllOption: true,
        multiple: false,
      });
      if (file) {
        const reader = new FileReader();
        reader.readAsDataURL(file);
        reader.onload = () => insert(reader.result);
      }
    },

    /**
     * @param { "ol" | "ul" | "ordered" | "unordered" } type
     */
    insertList(type = "ul") {
      let tagName = "ul";
      if (type === "ol" || type === "ordered") tagName = "ol";

      const list = document.createElement(tagName);
      const li = document.createElement("li");
      li.contentEditable = "plaintext-only";
      li.addEventListener("keydown", (e) => {
        if (e.key === "Enter") e.preventDefault();
      });
      list.appendChild(li);
      this.nextElementSibling.appendChild(list);
      li.focus();
    },

    insertListOrdered() {
      this.insertList("ol");
    },

    insertListUnordered() {
      this.insertList("ul");
    },

    /**
     * 去除空格（清除 p 元素中的空格）
     */
    clearSpace() {
      const contentElement = this.nextElementSibling;
      const elements = contentElement.children;
      for (let index = 0; index < elements.length; index++) {
        const e = elements[index];
        if (e.tagName === "P") {
          e.innerHTML = e.innerHTML.replaceAll(" ", "").replaceAll("\n", "");
        }
      }
    },
  };

  /**
   * @type { HTMLElement }
   */
  const cyueEditorBase = {
    init(toolbar = false) {
      const contentContainer = document.createElement("div");
      contentContainer.className = "cyue-editor-content";
      Object.assign(contentContainer, cyueEditorContentBase);
      contentContainer.init();
      this.contentContainer = contentContainer;
      this.appendChild(contentContainer);

      if (toolbar) {
        const toolbarContainer = document.createElement("div");
        toolbarContainer.className = "cyue-editor-toolbar";
        Object.assign(toolbarContainer, cyueEditorToolbarBase);
        toolbarContainer.init();
        this.toolbarContainer = toolbarContainer;
        this.insertBefore(toolbarContainer, contentContainer);
      }
    },

    clear() {
      this.contentContainer.innerHTML = "";
    },

    getHTML() {
      return this.contentContainer.getHTML();
    },

    getArticleContentXML() {
      // console.log(this.contentContainer.getArticleContentXML());
      return this.contentContainer.getArticleContentXML();
    },
  };

  return {
    /**
     * 初始化
     */
    init(toolbar = false) {
      /** @type { HTMLCollectionOf<HTMLDivElement> } */
      const editors = document.getElementsByClassName("editor");
      for (let index = 0; index < editors.length; index++) {
        let element = editors[index];
        Object.assign(element, cyueEditorBase);
        element.init(toolbar);
      }

      /** @type { HTMLCollectionOf<HTMLDivElement> } */
      const cyueEditors = document.getElementsByClassName("cyue-editor");
      for (let index = 0; index < cyueEditors.length; index++) {
        let element = cyueEditors[index];
        Object.assign(element, cyueEditorBase);
        element.init(toolbar);
      }
    },
  };
})();
